/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package _bai02_phantichphankhaibao;

import java.util.ArrayList;
import java.util.regex.*;
import javax.swing.JOptionPane;

/**
 *
 * @author Administrator
 */
public class jClass_PhanKhaiBao implements Interface_CacThanhPhanDacTa {

    private String _TenHam;
    private ArrayList<jClass_Bien> _CacThamSo;
    private jClass_Bien _GiaTriTraVe;
    private  static String _BieuThucDinhDang;
    /*/**
     * @return the _TenHam
     */

    public String getTenHam() {
        return _TenHam;
    }

    /**
     * @param TenHam the _TenHam to set
     */
    public void setTenHam(String TenHam) {
        this._TenHam = TenHam;
    }

    /**
     * @return the _CacThamSo
     */
    public ArrayList<jClass_Bien> getCacThamSo() {
        return _CacThamSo;
    }

    /**
     * @param CacThamSo the _CacThamSo to set
     */
    public void setCacThamSo(ArrayList<jClass_Bien> CacThamSo) {
        this._CacThamSo = CacThamSo;
    }

    /**
     * @return the _GiaTriTraVe
     */
    public jClass_Bien getGiaTriTraVe() {
        return _GiaTriTraVe;
    }

    /**
     * @param GiaTriTraVe the _GiaTriTraVe to set
     */
    public void setGiaTriTraVe(jClass_Bien GiaTriTraVe) {
        this._GiaTriTraVe = GiaTriTraVe;
    }

    public  jClass_PhanKhaiBao() {
        _CacThamSo = new ArrayList<jClass_Bien>();
        _GiaTriTraVe = new jClass_Bien();
        _TenHam = "";
        //_BieuThucDinhDang = "([a-zA-Z0-9._-]+)\\1+";
        //_BieuThucDinhDang = "^[a-zA-Z0-9_]+\\(([a-zA-Z0-9_]:[NnRrBbQqCc])+\\)([a-zA-Z0-9_]:[NnRrBbQqCc])?";
        /*  Với Regex này thì khi khai báo các biến cần phải khai báo thêm dấu ','
            ở phía sau biến sau cùng (phía trước dấu ')'). Cần nhớ điều này khi kiểm tra
            (Thêm dấu ',' ở vị trí thích hợp vào chuổi cần kiểm tra)
         */
        //Biểu thức hoàn chỉnh: "^[a-zA-Z0-9_]+\\s*\\(\\s*(([a-zA-Z0-9_]+\\s*:\\s*[a-zA-Z0-9_]\\s*,\\s*)|,*)+\\s*\\)\\s*[a-zA-Z0-9_]+\\s*:\\s*[a-zA-Z0-9_]?\\s*$";

        /*  Phần kiểm tra neo đầu, tên hàm với dấu phân cách tên hàm và phần còn lại
            là đoạn "^[a-zA-Z0-9_]+\\s*\\(" trong đoạn hoàn chỉnh phía trên
            tương đương "Max2Numbers("
        */
        _BieuThucDinhDang = "^"+ jEnum_ChuoiDinhDang.TenHam.value() +
                "\\s*" + jEnum_DauPhanCach.TenHam_PhanConLai.value();

        /*  Phần kiểm tra tên các biến, dấu phân cách tên biến_kiểu dữ liệu và dấu phân cách các biến với nhau
            là đoạn "\\s*([a-zA-Z0-9_]+\\s*:\\s*[NnRrBbQqCc]\\s*,\\s*)+" trong đoạn hoàn chỉnh phía trên
            tương đương "v1 : x, v2 : y," nên nhớ là dư một dấu ','
        */
        _BieuThucDinhDang += "\\s*(("+ jEnum_ChuoiDinhDang.TenBien.value() + "\\s*";
        _BieuThucDinhDang += jEnum_DauPhanCach.TenBien_KieuDuLieu.value() + 
                "\\s*" + jEnum_ChuoiDinhDang.KieuDuLieu.value() + "\\s*";
        _BieuThucDinhDang += jEnum_DauPhanCach.CacThamSoVoiNhau.value() + "\\s*)*|,)";

        /*  Phần kiểm tra tên dấu phân cách phần trả về với các tham số, phần trả về và neo cuối
            là đoạn "\\s*\\)\\s*[a-zA-Z0-9_]+\\s*:\\s*[NnRrBbQqCc]$" trong đoạn hoàn chỉnh phía trên
            tương đương ")return:R"
        */
        _BieuThucDinhDang += "\\s*" + jEnum_DauPhanCach.GiaTriTraVe_CacThamSo.value();
        _BieuThucDinhDang += "\\s*(" + jEnum_ChuoiDinhDang.TenBien.value() + "\\s*" +
                jEnum_DauPhanCach.TenBien_KieuDuLieu.value() + "\\s*" + jEnum_ChuoiDinhDang.KieuDuLieu.value() + ")?\\s*$";
    }

    /**
     *
     * @return chuổi kết quả để xuất ra màn hình. Có dạng:
     *      Tên hàm:    Max2Numbers
     *      Các biến:   số lượng: 2
     *          1.  Tên: x      Kiểu dữ liệu: N
     *          2.  Tên: y      Kiểu dữ liệu: R
     *      Trả về:
     *              Tên: result Kiểu dữ liệu: R
     *
     */
    @Override
    public String toString() {
    //Tạo chuổi: "Tên hàm:  "
        String Str_KetQua = jEnum_ThongTinBoSung.TenHam.value();
        Str_KetQua += jEnum_ThongTinBoSung.KhoangCachTrongMotPhan.value();

        //Bổ sung tên hàm:
        Str_KetQua += _TenHam.trim();
        Str_KetQua += jEnum_ThongTinBoSung.KhoangCachGiuaCacPhan.value();

    //Tạo chuổi: "Số lượng tham số: "
        Str_KetQua += jEnum_ThongTinBoSung.SoLuongThamSo.value();
        Str_KetQua += jEnum_ThongTinBoSung.KhoangCachTrongMotPhan.value();

        //Bổ sung số lượng tham số
        int i_SoLuongThamSo = _CacThamSo.size();
        Str_KetQua += String.valueOf(i_SoLuongThamSo);
        Str_KetQua += jEnum_ThongTinBoSung.KhoangCachGiuaChaCon.value();

    //Tạo chuổi: "Chi tiết các tham số:"
        Str_KetQua += jEnum_ThongTinBoSung.CacThamSo.value();

        //Tạo các chuổi thông tin chi tiết các tham số
        for (jClass_Bien jB_Tam : _CacThamSo) {
            Str_KetQua += jEnum_ThongTinBoSung.KhoangCachGiuaChaCon.value();
            Str_KetQua += jEnum_ThongTinBoSung.KhoangCachLuiGiuaChaCon.value();
            Str_KetQua += _CacThamSo.indexOf(jB_Tam) + 1 + ")" + jEnum_ThongTinBoSung.KhoangCachNho.value();
            Str_KetQua += jB_Tam.toString();
        }
        Str_KetQua += jEnum_ThongTinBoSung.KhoangCachGiuaCacPhan.value();

    //Tạo chuổi: "Trả về:  "
        Str_KetQua += jEnum_ThongTinBoSung.GiaTriTraVe.value();
        Str_KetQua += jEnum_ThongTinBoSung.KhoangCachGiuaChaCon.value();
        Str_KetQua += jEnum_ThongTinBoSung.KhoangCachTrongMotPhan.value();

        //Bổ sung giá trị trả về:
        Str_KetQua += _GiaTriTraVe.toString();
        Str_KetQua += jEnum_ThongTinBoSung.KhoangCachGiuaCacPhan.value();
        return Str_KetQua;
    }

    /**
     *
     * Tách chuổi và đưa và các thuộc tính của lớp jClass_PhaKhaiBao
     * @param Str_KhaiBao chuoi khai bao hop le vi du: Max2Numbers (v1: R, v2: R) result: R
     */
    public void jCapNhatTuChuoi(String Str_KhaiBao) {
        //Tách tên hàm ra khỏi các phần còn lại
        if (!jKiemTraChuoiHopDinhDang(Str_KhaiBao)){
            String mess = "Chuoi:\n" + Str_KhaiBao + "\n khong hop dinh dang cua mot phan Khai Bao!!!";
            JOptionPane.showMessageDialog(null, mess);
            throw new ExceptionInInitializerError(Str_KhaiBao);
        }
        String Str_KyTuTachChuoi = jEnum_DauPhanCach.TenHam_PhanConLai.value();
        String[] StrArr_TachTenHam = Str_KhaiBao.split(Str_KyTuTachChuoi);

        //Xác định tên hàm
        setTenHam(StrArr_TachTenHam[0]);

        //Tách giá trị trả về ra khỏi các tham số
        String[] StrArr_TachGiaTriTraVe = StrArr_TachTenHam[1].split(jEnum_DauPhanCach.GiaTriTraVe_CacThamSo.value());

        //Xác định biến trả về
        jClass_Bien jB_GiaTriTraVe = new jClass_Bien();

        if (StrArr_TachGiaTriTraVe.length > 1) //Nếu có giá trị trả về thì cập nhật
        {
            jB_GiaTriTraVe.jCapNhatTuChuoi(StrArr_TachGiaTriTraVe[1]);
        }
        //Nếu không sẽ trả về biến có tên là "" và khi xuất ra chuổi sẽ được "void"

        setGiaTriTraVe(jB_GiaTriTraVe);

        //Xác định các tham số
        //String Str_ChuoiCacThamSo = StrArr_TachGiaTriTraVe[0];
        //Lấy các chuổi chứa các thông tin về các tham số
        if (StrArr_TachGiaTriTraVe[0].trim().length() == 0){
            setCacThamSo(new ArrayList<jClass_Bien>(0));
            //if (StrArr_TachGiaTriTraVe[0].length() > 0){
            return;
        }
        String[] StrArr_CacThamSo = StrArr_TachGiaTriTraVe[0].split(jEnum_DauPhanCach.CacThamSoVoiNhau.value());
        //Đếm số lượng tham số
        int i_SoLuongThamSo = StrArr_CacThamSo.length;

        ArrayList<jClass_Bien> jB_CacThamSo = new ArrayList(i_SoLuongThamSo);
        for (int i = 0; i < i_SoLuongThamSo; i++) {
            jClass_Bien jB_Tam = new jClass_Bien();
            jB_Tam.jCapNhatTuChuoi(StrArr_CacThamSo[i]);
            jB_CacThamSo.add(jB_Tam);
        }
        setCacThamSo(jB_CacThamSo);
    }

    /**
     * @return the _BieuThucDinhDang
     */
    public static String getBieuThucDinhDang() {
        return _BieuThucDinhDang;
    }

    /**
     * @param BieuThucDinhDang the _BieuThucDinhDang to set
     */
    public static void setBieuThucDinhDang(String BieuThucDinhDang) {
        _BieuThucDinhDang = BieuThucDinhDang;
    }

    /**
     * Kiểm tra xem một chuổi có thỏa biểu thức định dạng không.
     * Nhớ thêm dấu ',' vào vị trí thích hợp (xem phần hàm khởi tạo để biết thêm chi tiết)
     * @param str_ChuoiCanKienTra
     * @return
     */
    public Boolean jKiemTraChuoiHopDinhDang (String str_ChuoiCanKienTra)    {
        String str_ChuoiDaBoSungDauPhanCach = str_ChuoiCanKienTra;
             str_ChuoiDaBoSungDauPhanCach = str_ChuoiCanKienTra.replaceAll("\\)", ",\\)");
        Pattern pat=Pattern.compile(_BieuThucDinhDang);
        Matcher matcher =pat.matcher(str_ChuoiDaBoSungDauPhanCach);
        return matcher.matches();
    }
    /**
     *
     * @return  số thứ tự của biến đầu tiên trùng tên với biến trước đó,
     *          hoặc -1 nếu là kết quả trả về, -2 nếu không có biến trùng.
     * Kiểm tra bằng cách loại bỏ các trường hợp trùng tên.
     */
    public int jKiemTraCacBienKhongTrungTen ()    {
        ArrayList<jClass_Bien> jBArr_CacThamSo= getCacThamSo();
        if (jBArr_CacThamSo.size() == 0)
            return -2; //Không có tham số thì làm gì có tam số trùng :)
        //Từ tham số đầu tiên đến tham số kế cuối (đã loại bỏ trường hợp tham số cuối cùng ở phía dưới)
        for (int i = 0; i < jBArr_CacThamSo.size() - 1; i++){
            for (int j = i + 1; j < jBArr_CacThamSo.size(); j++)
            //Kiểm tra từng cặp tham số thứ i với các tham số thứ >i
                if (jBArr_CacThamSo.get(i).getTen().compareTo(jBArr_CacThamSo.get(j).getTen()) == 0)
                    return j;
            //Kiểm tra tham số thứ i có trùng tên với giá trị trả về không
            if (jBArr_CacThamSo.get(i).getTen().compareTo(_GiaTriTraVe.getTen()) == 0)
                return -1;
        }
        //Nếu tham số cuối cùng có trùng tên với giá trị trả về không. Nếu có trả về false
        if (jBArr_CacThamSo.get(jBArr_CacThamSo.size() - 1).getTen().trim().compareTo(_GiaTriTraVe.getTen().trim()) == 0)
            return -1;
        //Không phát hiện trường hợp false trả về false.
        return -2;
    }
    /**
     *
     * @param str_ChuoiDuocNhap     Chuổi người dùng nhập vào cần kiểm tra xem chuổi nhập có lổi không
     * @return                      Lổi của chuổi
     */
    public jClass_Loi jKiemTraLoiCuaBieuThucDuocNhap (String str_ChuoiDuocNhap){
        //Kiểm tra định dạng chuổi
        if (!jKiemTraChuoiHopDinhDang(str_ChuoiDuocNhap))
            return new jClass_Loi(jEnum_Loi.ChuoiKhaiBaoSaiDinhDang, 0, "");
        jCapNhatTuChuoi(str_ChuoiDuocNhap);

        //Kiểm tra các biến không trùng tên
        int i_ViTriCuaBienTrungTenVoiBienTruocDo = jKiemTraCacBienKhongTrungTen();
        if (i_ViTriCuaBienTrungTenVoiBienTruocDo != -2)//Nếu có lỗi
            return new jClass_Loi(jEnum_Loi.CacBienTrungTen, 0, String.valueOf(i_ViTriCuaBienTrungTenVoiBienTruocDo));

        //Kiểm tra kiểu dữ liệu
        int i_ViTriCuaKieuDuLieuKhongHoTroDauTien = jKiemTraCacKieuDuLieuDuocHoTro();
        if (i_ViTriCuaKieuDuLieuKhongHoTroDauTien != -2)//Nếu có lỗi
            return new jClass_Loi(jEnum_Loi.KieuDuLieuKhongDuocHoTro, 0, String.valueOf(i_ViTriCuaKieuDuLieuKhongHoTroDauTien));
        return new jClass_Loi();
    }
    /**
     * Kiểm tra xem có kiệu dữ liệu không được hổ trợ không.
     * @return  số thứ tự của kiểu dữ liệu đầu tiên không được hổ trợ,
     *          hoặc -1 nếu là kết quả trả về, -2 nếu không có kiểu dữ liệu không được hộ trở.
     */
    public int jKiemTraCacKieuDuLieuDuocHoTro ()    {
        ArrayList<jClass_Bien> jBArr_CacThamSo= getCacThamSo();
        //Từ tham số đầu tiên đến tham số kế cuối (đã loại bỏ trường hợp tham số cuối cùng ở phía dưới)
        for (int i = 0; i < jBArr_CacThamSo.size(); i++)
            if (!jBArr_CacThamSo.get(i).jKiemTraKieuDuLieu())
                return i;
        //Nếu kiểu dữ liệu của giá trị trả về có lỗi trả về -1
        if (!_GiaTriTraVe.getKieuDuLieu().equals("") && !_GiaTriTraVe.jKiemTraKieuDuLieu())
            return -1;
        //Không phát hiện trường hợp lỗi trả về -2;
        return -2;
    }

    public String jCSharpCode(int DoLui) {

        jClass_PhanKhaiBao jPKB_KhaiBao = this;
        //Lùi code và một đoạn hợp lý (dựa vào cấp độ) và thêm kiểu dữ liệu trả về và " ("
        String str_KetQua = "";
        str_KetQua += jClass_BoTaoCode.jTaoCapDo(DoLui) + " static "+
                jClass_BoTaoCode.jChuyenKieuDuLieuCS(jPKB_KhaiBao.getGiaTriTraVe().getKieuDuLieu()) +
                " " ;
        str_KetQua += jPKB_KhaiBao.getTenHam()+" "+ "(";
        //ví dụ đoạn code hiện tại: int (
        //Them ten ham

        //Thêm danh sách tham số
        for (jClass_Bien bien : jPKB_KhaiBao.getCacThamSo()){
            //Thêm kiểu dữ liệu và ' '
            str_KetQua += jClass_BoTaoCode.jChuyenKieuDuLieuCS(bien.getKieuDuLieu()) + " ";
            //Thêm tên biến và ", "
            str_KetQua += bien.getTen() + ","+
                    " ";
            //ví dụ đoạn code hiện tại "int (int a, "
        }
        //ví dụ đoạn code hiện tại "int (int a, int b, "
        //Loại bỏ ", " dư (nếu có)
        if (str_KetQua.contains("," + " "))
            str_KetQua = str_KetQua.substring(0, str_KetQua.lastIndexOf("," +
                    " "));

        //Thêm ') '
        str_KetQua += ")";
        //ví dụ đoạn code hiện tại "int (int a, int b)"
        //Thêm dấu xuống dòng, "{" và dấu xuống dòng
        //str_KetQua += jClass_BoTaoCode.jTaoCapDo(DoLui) + "\n{\n";

        /**ví dụ đoạn code hiện tại "int (int a, int b)
         *                          {
         *                              "
         * Kể từ đây vì chỉ minh họa từng dòng code
         */

        //-------------------Đoạn code thực hiện chương trình-------------------
        //Tăng cấp độ
        /*DoLui++;
        //Khai báo biến trả về (nếu có) ví dụ: "int result = 0;\n"
        if (jPKB_KhaiBao.getGiaTriTraVe().getTen().length() != 0)
                str_KetQua += jClass_BoTaoCode.jTaoCapDo(DoLui) + jClass_BoTaoCode.jTaoKhaiBaoBien(jPKB_KhaiBao.getGiaTriTraVe()) + "\n";

        //Tạo phần trả về ví dụ: "return result;\"
        str_KetQua += jClass_BoTaoCode.jTaoCapDo(DoLui) + "return " + jPKB_KhaiBao.getGiaTriTraVe().getTen() + ";\n";
        //-----------------Kết thục đoạn code thực hiện chương trình------------

        //Giảm cấp độ và tạo dấu "}"
        str_KetQua += jClass_BoTaoCode.jTaoCapDo(--DoLui) + "}";
        */return str_KetQua;

    }

    public String jToCCode(int DoLui) {
        jClass_PhanKhaiBao jPKB_KhaiBao = this;
        //Lùi code và một đoạn hợp lý (dựa vào cấp độ) và thêm kiểu dữ liệu trả về và " ("
        String str_KetQua = "";
        str_KetQua += jClass_BoTaoCode.jTaoCapDo(DoLui) +
                jClass_BoTaoCode.jChuyenKieuDuLieu(jPKB_KhaiBao.getGiaTriTraVe().getKieuDuLieu()) +
                " " ;
        str_KetQua += jPKB_KhaiBao.getTenHam()+" "+ "(";
        //ví dụ đoạn code hiện tại: int (
        //Them ten ham

        //Thêm danh sách tham số
        for (jClass_Bien bien : jPKB_KhaiBao.getCacThamSo()){
            //Thêm kiểu dữ liệu và ' '
            str_KetQua += jClass_BoTaoCode.jChuyenKieuDuLieu(bien.getKieuDuLieu()) + " ";
            //Thêm tên biến và ", "
            str_KetQua += bien.getTen() + ","+
                    " ";
            //ví dụ đoạn code hiện tại "int (int a, "
        }
        //ví dụ đoạn code hiện tại "int (int a, int b, "
        //Loại bỏ ", " dư (nếu có)
        if (str_KetQua.contains("," + " "))
            str_KetQua = str_KetQua.substring(0, str_KetQua.lastIndexOf("," +
                    " "));

        //Thêm ') '
        str_KetQua += ")";
        return str_KetQua;
    }

    public String jVBNetCode(int DoLui) {
         jClass_PhanKhaiBao jPKB_KhaiBao = this;
        //Lùi code và một đoạn hợp lý (dựa vào cấp độ) và thêm kiểu dữ liệu trả về và " ("
        String str_KetQua = "";
        
        str_KetQua += jPKB_KhaiBao.getTenHam()+" "+ "(";
        //ví dụ đoạn code hiện tại: int (


        //Thêm danh sách tham số
        for (jClass_Bien bien : jPKB_KhaiBao.getCacThamSo()){
            //Thêm kiểu dữ liệu và ' '
            str_KetQua += jClass_BoTaoCode.jChuyenKieuDuLieu(bien.getKieuDuLieu()) + " ";
            //Thêm tên biến và ", "
            str_KetQua += "AS ";
            str_KetQua += bien.getTen() + ","+
                    " ";
            //ví dụ đoạn code hiện tại "int (int a, "
        }
        //ví dụ đoạn code hiện tại "int (int a, int b, "
        //Loại bỏ ", " dư (nếu có)
        if (str_KetQua.contains("," + " "))
            str_KetQua = str_KetQua.substring(0, str_KetQua.lastIndexOf("," +
                    " "));

        //Thêm ') '
        str_KetQua += ")";
        str_KetQua += " AS ";
        str_KetQua += jClass_BoTaoCode.jTaoCapDo(DoLui) +
                jClass_BoTaoCode.jChuyenKieuDuLieu(jPKB_KhaiBao.getGiaTriTraVe().getKieuDuLieu()) +
                " " ;
        return str_KetQua;
    }
}
